﻿using UnityEngine;
using System;
using System.Collections;

[AddComponentMenu("TagMachine/Game Modes/Classic")]
public class GameModeClassic : PauseSystem 
{
	private const int MAX_JOYSTICKS 				= 8;

	protected static GameModeClassic s_Instance 	= null;
	public static GameModeClassic Instance
	{
		get
		{
			if ( Exists )
			{
				return s_Instance;
			}

			return null;
		}
	}
	public static bool Exists
	{
		get
		{
			if ( s_Instance == null )
			{
				s_Instance = GameObject.FindObjectOfType< GameModeClassic >();
			}
			return (s_Instance);
		}
	}

	// Players info
	public GameObject PlayerPrefab;
	public Color[] PlayerColors;
	public string SpawnPointTag 			= "SpawnPoint";
	public bool OnlyControllers				= true;

	// Game mode info
	public bool InfectionMode 				= false;	
	public int RoundTime					= 180;

	// Misc infos
	public int ScoreMultiplier 				= 100;
	public float WolfMinDistance			= 0.8f;	

	public float StartTimeWithoutPoints		= 1.0f;
	private float m_CurrentStartTimeWithoutPoints = 0.0f;

	// Picking component
	private WolfPickingAtStart m_PickingComponent = null;
	public WolfPickingAtStart PickingComponent
	{
		get
		{
			if ( m_PickingComponent == null )
			{
				m_PickingComponent = GetComponent< WolfPickingAtStart > ();
			}
			return m_PickingComponent;
		}		
	}
	public bool IsPickingWolf 				
	{ 
		get
		{
			return PickingComponent != null && PickingComponent.enabled;
		}
	}

	public int CurrentRound 				{ get; protected set; }
	public int NumRounds					{ get; protected set; }
	public bool IsGameEnded 				{ get { return CurrentRound >= NumRounds; } }

	protected Timer m_GameTimer				= null;
	public float RemainingTime 				{ get { return m_GameTimer.RemainingTime; } }

	protected PlayerEntity[] m_Players		= null;
	public int NumPlayers 					{ get; private set; }

	protected int[] m_PlayerRoundScores 	= null;
	protected int[] m_PlayerTotalScores 	= null;

	public PlayerEntity CurrentWolf 		{ get; protected set; }
	protected Fugitive m_CurrentWinner		= null;

	protected SafeArea[] m_Areas			= null;

	// Start of game
	protected virtual void SetupFromPreferences()
	{
		if ( PlayerPrefs.HasKey( "OnlyControllers" ) )
		{
			OnlyControllers = PlayerPrefs.GetInt( "OnlyControllers" ) == 0 ? false : true;
		}
		if ( PlayerPrefs.HasKey( "InfectionMode" ) )
		{
			InfectionMode = PlayerPrefs.GetInt( "InfectionMode" ) == 0 ? false : true;
		}
		if ( PlayerPrefs.HasKey( "RoundTime" ) )
		{
			RoundTime = PlayerPrefs.GetInt( "RoundTime" ) * 60;
		}


		if ( PlayerPrefs.HasKey( "ScoreMultiplier" ) )
		{
			ScoreMultiplier = PlayerPrefs.GetInt( "ScoreMultiplier" );
		}
		if ( PlayerPrefs.HasKey( "WolfMinDistance" ) )
		{
			WolfMinDistance = PlayerPrefs.GetFloat( "WolfMinDistance" );
		}
		if ( PlayerPrefs.HasKey( "StartTimeWithoutPoints" ) )
		{
			StartTimeWithoutPoints = PlayerPrefs.GetFloat( "StartTimeWithoutPoints" );
		}
	}

	protected virtual void ClearPreferences()
	{
		PlayerPrefs.DeleteKey( "OnlyControllers" );
		PlayerPrefs.DeleteKey( "InfectionMode" );
		PlayerPrefs.DeleteKey( "RoundTime" );


		PlayerPrefs.DeleteKey( "ScoreMultiplier" );
		PlayerPrefs.DeleteKey( "WolfMinDistance" );
		PlayerPrefs.DeleteKey( "StartTimeWithoutPoints" );
	}

	protected virtual void Awake()
	{
		SetupFromPreferences();

		m_PickingComponent 			= GetComponent< WolfPickingAtStart > ();

		// Create timer
		m_GameTimer 				= gameObject.AddComponent< Timer > ();
		m_GameTimer.StartOnAwake 	= false;
		m_GameTimer.DestroyOnEnd 	= false;
		m_GameTimer.RestartTimes	= 1;
		m_GameTimer.Duration 		= RoundTime;
		m_GameTimer.TimerCallbackEvent += EndRound;
	}

	protected virtual void Start()
	{
		// Setup num players
		NumPlayers 					= Input.GetJoystickNames().Length;
		if ( NumPlayers > MAX_JOYSTICKS )
		{
			NumPlayers 				= MAX_JOYSTICKS;
		}
		// Do we add the keyboard ?
		if ( !OnlyControllers )
		{
			++NumPlayers;
		}

		// Create players
		m_Players 					= new PlayerEntity[ GameModeClassic.Instance.NumPlayers ];

		for (int i = 0; i < m_Players.Length; ++i )
		{
			GameObject NewPlayer 	= Instantiate( PlayerPrefab ) as GameObject;
			NewPlayer.name 			= "Player" + i;

			m_Players[i] 			= NewPlayer.GetComponent< PlayerEntity >();
			m_Players[i].GetComponent< MovingEntity >().NumPlayer 			= i;
			m_Players[i].GetComponentInChildren< Fugitive >().BaseColor 	= PlayerColors[i];
		}

		// Setup players infos
		m_PlayerRoundScores 		= new int[ NumPlayers ];
		m_PlayerTotalScores 		= new int[ NumPlayers ];

		NumRounds					= NumPlayers;
		
		m_Areas						= GameObject.FindObjectsOfType< SafeArea > ();

		Restart();
	}

	void OnDestroy()
	{
		ClearPreferences();
	}

	// Game Status
	public override void Pause()
	{
		base.Pause();

		if ( !IsPickingWolf && !IsGameEnded )
		{
			foreach ( PlayerEntity Player in m_Players )
			{
				Player.GetComponent< MovingEntity >().enabled = false;
			}
		}

		m_GameTimer.Pause();
		if ( PickingComponent != null )
		{
			PickingComponent.Pause();
		}
	}

	public override void Unpause()
	{
		base.Unpause();

		if ( !IsPickingWolf && !IsGameEnded )
		{
			foreach ( PlayerEntity Player in m_Players )
			{
				Player.GetComponent< MovingEntity >().enabled = true;
			}
		}

		m_GameTimer.Unpause();
		if ( PickingComponent != null )
		{
			PickingComponent.Unpause();
		}
	}

	public void Restart()
	{
		CurrentRound = 0;

		for ( int i = 0; i < m_Players.Length; ++i )
		{
			m_PlayerRoundScores[i] 	= 0;
			m_PlayerTotalScores[i] 	= 0;
		}

		NextRound();
	}

	// Round change
	void NextRound()
	{
		Unpause();
		m_GameTimer.Pause();

		foreach ( PlayerEntity Player in m_Players )
		{
			Player.Reset();
		}

		foreach ( SafeArea Area in m_Areas )
		{
		    Area.Reset();
		}

		if ( !IsGameEnded && PickingComponent != null )
		{
			PickingComponent.Restart();
		}
	}

	public void StartRound()
	{		
		m_GameTimer.Restart();
	}

	protected virtual void EndRound()
	{
		++CurrentRound;
		
		for ( int i = 0; i < m_Players.Length; ++i )
		{
			m_PlayerTotalScores[i] 	+= m_PlayerRoundScores[i];
			m_PlayerRoundScores[i] 	= 0;
		}

		CurrentWolf = null;

		NextRound();
	}

	// Wolf Change
	public virtual void SwitchWolf( PlayerEntity _NewWolf )
	{
		if ( !InfectionMode && CurrentWolf != null )
		{
			CurrentWolf.Switch();
		}

		CurrentWolf = _NewWolf;

		CurrentWolf.Switch();
	}

	// Accessors on scores
	public int GetPlayerScoreRound( int _NumPlayer )
	{
		return m_PlayerRoundScores[_NumPlayer];
	}

	public int GetPlayerScoreTotal( int _NumPlayer )
	{
		return m_PlayerTotalScores[_NumPlayer];
	}

	void Update()
	{
		if ( !IsPickingWolf && !IsGameEnded )
		{
			Fugitive CurrentWinner = null;
			int PlayerWinner = -1,
				ScoreWinner = 0,
				NumWolfs = 0;

			for ( int i = 0; i < m_Players.Length; ++i )
			{
				if ( m_Players[i].IsWolf )
				{
					++NumWolfs;
				}
				else
				{
					if ( m_CurrentStartTimeWithoutPoints <= 0.0f )
					{
						if ( !m_Players[i].FugitiveComp.IsSafe && !m_Players[i].IsSwitching &&
							CurrentWolf != null && !CurrentWolf.IsSwitching ) 
						{
							float DistFromWolf = 
								Vector3.SqrMagnitude( m_Players[i].transform.position - CurrentWolf.transform.position );
							if ( DistFromWolf < WolfMinDistance )
							{
								DistFromWolf = WolfMinDistance;
							}

							m_PlayerRoundScores[i] += (int)(ScoreMultiplier / DistFromWolf);
						}

						if (PlayerWinner == -1 || 
							m_PlayerRoundScores[i] > ScoreWinner)

						{
							CurrentWinner = m_Players[i].FugitiveComp;

							PlayerWinner 	= i;
							ScoreWinner		= m_PlayerRoundScores[i];
						}
					}
					else
					{
						m_CurrentStartTimeWithoutPoints -= Time.deltaTime;
					}
				}
			}

			if ( CurrentWinner != null && m_CurrentWinner != CurrentWinner )
			{
				if ( m_CurrentWinner != null )
				{
					m_CurrentWinner.SetLoser();
				}
				CurrentWinner.SetWinner();
				m_CurrentWinner = CurrentWinner;
			}

			if ( NumWolfs >= m_Players.Length )
			{
				EndRound();
			}
		}
	}
}
